package com.elasticsearch.elasticsearchapi;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.apache.http.HttpHost;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.core.TimeValue;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.xcontent.XContentType;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

/**
 * es搜索功能优化前
 * @author ycx
 * @date 2025-05-16 21:33
 */
@SpringBootTest
public class ElasticsearchDemo {
    private static final String INDEX_NAME = "books";
    private RestHighLevelClient client;

    public ElasticsearchDemo() {
        // 初始化Elasticsearch客户端
        client = new RestHighLevelClient(
            RestClient.builder(new HttpHost("localhost", 9200, "http")));
    }

    public void close() {
        try {
            client.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 初始化测试数据
    public void initData() throws IOException {
        // 创建几个测试文档
        indexBook("1", "Java编程思想", "Bruce Eckel", "计算机编程");
        indexBook("2", "Effective Java", "Joshua Bloch", "计算机编程");
        indexBook("3", "深入理解Java虚拟机", "周志明", "计算机编程");
        indexBook("4", "数据结构与算法分析", "Mark Allen Weiss", "计算机基础");
        indexBook("5", "活着", "余华", "文学");
        indexBook("6", "平凡的世界", "路遥", "文学");
        indexBook("7", "Elasticsearch实战", "Radek Simko", "大数据");
        indexBook("8", "Python数据分析实战", "Sebastian Raschka", "大数据");
        indexBook("9", "Spring实战", "Craig Walls", "计算机编程");
        indexBook("10", "高性能MySQL", "Baron Schwartz", "数据库");

        System.out.println("数据初始化完成");
    }

    // 索引图书文档
    private void indexBook(String id, String title, String author, String category) throws IOException {
        Map<String, Object> jsonMap = new HashMap<>();
        jsonMap.put("id", id);
        jsonMap.put("title", title);
        jsonMap.put("author", author);
        jsonMap.put("category", category);

        IndexRequest indexRequest = new IndexRequest(INDEX_NAME)
            .id(id)
            .source(jsonMap, XContentType.JSON);

        IndexResponse indexResponse = client.index(indexRequest, RequestOptions.DEFAULT);
        System.out.printf("Indexed document with ID: %s, status: %s%n",
            indexResponse.getId(), indexResponse.status());
    }

    // 执行搜索
    public void search(String keyword) throws IOException {
        System.out.printf("搜索关键词: '%s'%n", keyword);

        SearchRequest searchRequest = new SearchRequest(INDEX_NAME);
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        // 构建多字段搜索查询
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        // 对title字段进行模糊搜索
        MatchQueryBuilder titleQuery = QueryBuilders.matchQuery("title", keyword)
            .fuzziness("AUTO"); // 自动计算模糊度

        // 对author字段进行模糊搜索
        MatchQueryBuilder authorQuery = QueryBuilders.matchQuery("author", keyword)
            .fuzziness("AUTO");

        // 对category字段进行模糊搜索
        MatchQueryBuilder categoryQuery = QueryBuilders.matchQuery("category", keyword)
            .fuzziness("AUTO");

        // 将三个查询条件用should连接，表示或关系
        boolQuery.should(titleQuery)
            .should(authorQuery)
            .should(categoryQuery);

        sourceBuilder.query(boolQuery);
        searchRequest.source(sourceBuilder);

        // 执行搜索
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);

        // 处理搜索结果
        System.out.printf("找到 %d 个匹配结果%n", searchResponse.getHits().getTotalHits().value);
        for (SearchHit hit : searchResponse.getHits()) {
            Map<String, Object> source = hit.getSourceAsMap();
            System.out.printf("ID: %s, 书名: %s, 作者: %s, 分类: %s, 得分: %.2f%n",
                source.get("id"),
                source.get("title"),
                source.get("author"),
                source.get("category"),
                hit.getScore());
        }
        System.out.println("-----------------------------------");
    }

    public static void main(String[] args) {
        ElasticsearchDemo demo = new ElasticsearchDemo();

        try {
            // 初始化数据
            demo.initData();

            // 等待索引刷新
            Thread.sleep(5000);

            // 测试汉字搜索
            demo.search("Java");
            demo.search("java"); // 测试不区分大小写
            demo.search("数据");

            // 测试模糊搜索
            demo.search("Elastic"); // 部分匹配
            demo.search("余");     // 部分匹配
            demo.search("深入Java"); // 跨词匹配

            // 测试错别字搜索
            demo.search("Java编称思想"); // 包含错别字
            demo.search("活着着");      // 多余字符

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            demo.close();
        }
    }
    //测试es查询
    @Test
    public void testSearch() throws IOException{
        ElasticsearchDemo elasticsearchDemo = new ElasticsearchDemo();
        elasticsearchDemo.search("Elastic");
    }

    //清空索引数据，并保留索引结构
    @Test
    void tranIndex() {
        DeleteByQueryRequest deleteRequest = new DeleteByQueryRequest("books")
            .setQuery(QueryBuilders.matchAllQuery())
            .setBatchSize(1000)  // 每批处理的文档数
            .setRefresh(true)    // 删除后刷新索引
            .setTimeout(TimeValue.timeValueMinutes(2));
        BulkByScrollResponse response = null;
        try {
            response = client.deleteByQuery(deleteRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("删除完成: " + response.getDeleted() + " 个文档");
    }
}
